Here you will learn: - DevTools HTML as entry - Create DevTool Panel - Create SideBar Pane How to use: - This tutorial is for Concept studying only. It's not written for you to follow along and code. That's for a later challenge. --- ## Entry Point To implement DevTools panels, you have to set a HTML entry point at manifest.json as: ``` "devtools_page": "devtools.html" ``` Anything visual in the html file is ignored. Google decided you must start the js file from a html file. The js file that devtools.html loads in, eg. devtools.js, is the one with the logic that opens a regular DevTools panel or DevTools side panel. The reason why Google decided to use the html file as an entry point is that it gives you the flexibility of splitting devtools.js into multiple js files for your organization/modularization purposes. At this section we will only use one file. At a later section in this document, we will cover modularization by breaking the devtools.js into multiple js files for organizational purposes. devtools.html (entrypoint whose layout and visuals are not as important as its ability to load in js files): ```
``` devtools.js code below for both DevTools panel and DevTools sidebar pane: ## DevTools Panel In this example, the devtools.js loaded in a devtools panel called "DevTools_Panel" (See the new tab): ``` let panelWindow; // Then you can programatically modify the panel layout chrome.devtools.panels.create("DevTools_Panel", "icon.png", "panel.html", panel => { // Code invoked on panel creation panel.onShown.addListener((window) => { panelWindow = window; }); // shown panel }); ``` ![[Pasted image 20250403200742.png]] Example use case: Grabs the fonts, colors, etc of the webpage into where you usually inspect styles at the DevTools panel (instead of side panel or popup). Implications: DevTools code can access the web content and programmatically read for the colors, font-families, and spacing ![[Pasted image 20250402014818.png]] The presentation initiating for the DevTools Pane points to a html file. Your html file which is `sidebar.html` in this case, can load in js and css files and its HTML will be rendered in the panel (unlike entry point devtools.html whose elements are never rendered). Let's say panel.html loads panel.js. That javascript will often have onclick handlers for the panel elements, and the usual code pattern is to send messages (`sendMessage`) for devtools.js to listen and respond to. That devtools.js would execute the presentation or business code, usually writing to the web content (via chrome.scripting.executeScript). But you could localize the code to panel.js itself instead of sending the message for devtools.js to pick up, eg. panel.js can also write to web content. ## DevTools Sidebar Pane Here the devtools.js loads in a Devtools sidebar pane called "Design Templates" under the Elements panel: ``` let sidebar = null; // Then you can programatically modify the sidebar layout // Initialize the sidebar for the Elements panel chrome.devtools.panels.elements.createSidebarPane("DevTools_Sidebar", (mySidebar) => { // Set the HTML file for the sidebar mySidebar.setPage('devt-sidebar.html'); // Code invoked on panel creation mySidebar.onShown.addListener((sidebarWindow) => { console.log("DevTools_Sidebar is shown"); sidebar = sidebarWindow; }); // Log when the sidebar is hidden mySidebar.onHidden.addListener(() => { console.log("DevTools_Sidebar is hidden"); }); }); ``` - Principle: The Elements panel where you modify or inspect the webpage has many sidebar panes such as Styles, Computed, Layout, Event Listeners, etc. Usually the sidebar pane goes into more detail on the element that's selected or inspected from the Inspection window (the webpage while DevTools is opened) or the the rows of code in Elements panel. - Example Use Case; We add a "Design Templates" sidebar pane that lets you swap out inspected elements with pre-designed templates ![[Pasted image 20250402015459.png]] The presentation initiating for the Sidebar pane points to a html file. Your html file which is `sidebar.html` in this case, can load in js and css files and its HTML will be rendered in the sidebar (unlike entry point devtools.html whose elements are never rendered). Let's say sidebar.html loads sidebar.js. That javascript will often have onclick handlers for the sidebar elements, and the usual code pattern is to send messages (`sendMessage`) for devtools.js to listen and respond to. That devtools.js would execute the presentation or business code, usually writing to the web content (via chrome.scripting.executeScript). But you could localize the code to sidebar.js itself instead of sending the message for devtools.js to pick up, eg. sidebar.js can also write to web content. --- ## Summary - Devtools.js, DevTools Panel, DevTools Element Sidebar Pane While devtools.html is the entry point for manifest.js, devtools.js gets loaded into devtools.html, and devtools.js is where you programmatically initiate a DevTools panel or an Elements sidebar pane. You are not required to have both types of presentations. ## More modularization As you add initiating presentations, onMessage, on Element/Inspect change, the devtools.js could get very long. You may want to break it up into three files. You can rename everything that does with initiating using prefix "init". - manifest.json: ``` "devtools_page": "init-devtools.html" ``` - init-devtools.html: ``` ``` ^ You want init-devtools.js loaded after your init presentation js files, in case you are saving the presentation instances globally and then any onMessage handlers or code at init-devtools.js relies on those global variables. - init-devtools-panel.js ``` let panelWindow; chrome.devtools.panels.create("DevTools_Panel", "icon.png", "devt-panel.html", panel => { // code invoked on panel creation panel.onShown.addListener((window) => { panelWindow = window; }); // shown panel }); ``` - init-devtools-sidebar.js: ``` let sidebar = null; // Initialize the sidebar for the Elements panel chrome.devtools.panels.elements.createSidebarPane("DevTools_Sidebar", (mySidebar) => { // Set the HTML file for the sidebar mySidebar.setPage('devt-sidebar.html'); // Log when the sidebar is shown mySidebar.onShown.addListener((sidebarWindow) => { console.log("DevTools_Sidebar is shown"); sidebar = sidebarWindow; }); // Log when the sidebar is hidden mySidebar.onHidden.addListener(() => { console.log("DevTools_Sidebar is hidden"); }); }); ``` - init-devtools.js: ``` async function insertCDNs(doneCallback) { await chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { let tab = tabs[0]; chrome.scripting.insertCSS({ target: {tabId: tab.id}, files: ['assets-framework-css/bootstrap.min.css', 'assets-framework-css/tailwind.min.css', 'assets-framework-css/animations.css'] }); chrome.scripting.executeScript({ target: {tabId: tab.id}, files: ['assets-framework-css/bootstrap.bundle.min.js'] }); console.log("CSS and JS injected for Bootstrap 5 / Tailwind 2.") console.log("CSS injected for animations fade-in-fade-out and wiggle.") }); doneCallback(); }; // insertCDNs document.addEventListener("DOMContentLoaded", function() { insertCDNs(()=>{ document.querySelector("#status-inject-css-files-into-content").innerHTML = "Ready.CSS and JS injected for Bootstrap 5 / Tailwind 2. CSS injected for animations fade-in-fade-out and wiggle." }); document.querySelector("#toggle-border").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-toggle-border"}); }); document.querySelector("#toggle-shadow").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-toggle-shadow"}); }); document.querySelector("#animate-fade-in-out").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-animate-fade-in-out"}); }); document.querySelector("#animate-wiggle").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-animate-wiggle"}); }); document.querySelector("#toggle-visibility").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-toggle-visibility"}); }); document.querySelector("#toggle-display").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-toggle-display"}); }); document.querySelector("#invert-inspected-window-colors").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-invert-inspected-window-colors"}); }); document.querySelector("#get-inspected-element").addEventListener("click", () => { chrome.runtime.sendMessage({type:"sb2dt-request-inspected-element"}, (response) => { console.log(`response: ${response}`); }); }); }); chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { switch(request.type) { case "dt2sb-response-inspected-element": document.querySelector("#status-inspected-element").innerHTML = request.data; break; } }); ``` Instead of panel.html, panel.js, panel.css, sidebar.html, sidebar.js, sidebar.css, which makes the files difficult to navigate in VS Code. You can prefix them with devt or dt instead, which is shortened or abbreviated to hint it's not as important, or it's a piece of, the bigger entry point `init-devtools`. So the folder structure has prefixes init or devt for all html, css, js files of Devtools panel/sidebar: ``` . ├── assets-icons/ ├── devt-panel.html ├── devt-panel.js ├── devt-sidebar.html ├── devt-sidebar.js ├── init-devtools-panel.js ├── init-devtools-sidebar.js ├── init-devtools.html ├── init-devtools.js └── manifest.json ``` We will cover the sidebar and panel implementations at a later tutorial. Again, this document is not written for you to follow along and code. That's for a later challenge.